package com.hopes.bizz.poll.statistic.service.impl;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.hopes.bizz.common.core.util.CollectionUtils;
import com.hopes.bizz.common.core.util.DateUtils;
import com.hopes.bizz.common.core.util.StringUtils;
import com.hopes.bizz.poll.analy.dto.AnalyzeTrendDTO;
import com.hopes.bizz.poll.analy.dto.CompareAnalysisDTO;
import com.hopes.bizz.poll.analy.dto.CompareTrendDTO;
import com.hopes.bizz.poll.analy.dto.GISAnalyzeDischargeDTO;
import com.hopes.bizz.poll.analy.vo.CompareAnalysisVo;
import com.hopes.bizz.poll.analy.vo.CompareTrendVO;
import com.hopes.bizz.poll.common.constant.AnalyzeTrendConstant;
import com.hopes.bizz.poll.common.constant.GISAnalyzeConstant;
import com.hopes.bizz.poll.factor.entity.PollDisplayFactorEntity;
import com.hopes.bizz.poll.factor.entity.PollFactorInfoEntity;
import com.hopes.bizz.poll.factor.service.PollDisplayFactorService;
import com.hopes.bizz.poll.factor.service.PollFactorInfoService;
import com.hopes.bizz.poll.monitor.entity.PollMonitorFactorEntity;
import com.hopes.bizz.poll.monitor.entity.PollMonitorSiteEntity;
import com.hopes.bizz.poll.monitor.service.PollMonitorFactorService;
import com.hopes.bizz.poll.monitor.service.PollMonitorSiteService;
import com.hopes.bizz.poll.om.entity.BaseOmDataEntity;
import com.hopes.bizz.poll.om.entity.PollDayEntity;
import com.hopes.bizz.poll.om.entity.PollHourEntity;
import com.hopes.bizz.poll.om.helper.PollDataTimeParse;
import com.hopes.bizz.poll.om.service.PollDayService;
import com.hopes.bizz.poll.om.service.PollHisDataService;
import com.hopes.bizz.poll.om.service.PollHourService;
import com.hopes.bizz.poll.om.service.PollMinService;
import com.hopes.bizz.poll.statistic.service.DataTrendAnalyzeService;
import com.hopes.bizz.poll.statistic.service.support.StatisticAnalyzeSupport;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author yumr
 * @ProjectName bizz
 * @Description 数据趋势分析
 * @time 2023/5/30 10:59
 */
@Service
@RequiredArgsConstructor
public class DataTrendAnalyzeServiceImpl extends StatisticAnalyzeSupport implements DataTrendAnalyzeService {


    private final PollMinService pollMinService;
    private final PollDayService pollDayService;
    private final PollHourService pollHourService;
    private final PollFactorInfoService pollFactorInfoService;
    private final PollMonitorFactorService pollMonitorFactorService;
    private final PollMonitorSiteService pollMonitorSiteService;
    private final PollDisplayFactorService pollDisplayFactorService;
    private final PollHisDataService pollHisDataService;

    /**
     * 数据趋势分析
     *
     * @param analyzeTrendDTO 查询对象
     * @return 结果
     */
    @Override
    public JSONArray listData(AnalyzeTrendDTO analyzeTrendDTO) {

        // 1、获取需要展示的站点
        final List<Long> siteList = analyzeTrendDTO.getMonitorSiteList();
        final LambdaQueryWrapper<PollMonitorSiteEntity> monitorSiteWrapper = Wrappers.
                <PollMonitorSiteEntity>lambdaQuery().in(CollectionUtils.isNotEmpty(siteList), PollMonitorSiteEntity::getId, siteList);
        final List<PollMonitorSiteEntity> monitorSiteList = pollMonitorSiteService.list(monitorSiteWrapper);

        // 2、获取需要展示的因子
        List<PollFactorInfoEntity> monitorFactorList = null;
        final List<Long> factorList = analyzeTrendDTO.getMonitorFactorList();
        if (CollectionUtils.isEmpty(factorList)) {
            final String monitorType = monitorSiteList.stream().map(PollMonitorSiteEntity::getMonitorType).findFirst().orElse(null);
            if (null != monitorType) {
                monitorFactorList = pollDisplayFactorService.getDisplayFactorByMonitorType(monitorType);
            }
        } else {
            final LambdaQueryWrapper<PollFactorInfoEntity> wrapper = Wrappers.
                    <PollFactorInfoEntity>lambdaQuery().in(CollectionUtils.isNotEmpty(factorList), PollFactorInfoEntity::getId, factorList);
            monitorFactorList = pollFactorInfoService.list(wrapper);
        }
        if (CollectionUtils.isEmpty(monitorFactorList)) {
            return new JSONArray();
        }
        final List<String> factorCodeList = monitorFactorList.stream().map(PollFactorInfoEntity::getCode).collect(Collectors.toList());
        if (analyzeTrendDTO.getDateType().equals(AnalyzeTrendConstant.DATA_TYPE_MIN)) {
            return this.listOmMin(analyzeTrendDTO, monitorSiteList, monitorFactorList, factorCodeList, DateUtils::dateLimitMinute);
        } else if (analyzeTrendDTO.getDateType().equals(AnalyzeTrendConstant.DATA_TYPE_HOUR)) {
            return this.listOmHour(analyzeTrendDTO, monitorSiteList, monitorFactorList, factorCodeList, DateUtils::dateLimitHour);
        } else if (analyzeTrendDTO.getDateType().equals(AnalyzeTrendConstant.DATA_TYPE_DAY)) {
            return this.listOmDay(analyzeTrendDTO, monitorSiteList, monitorFactorList, factorCodeList, DateUtils::dateLimitDay);
        } else {
            return new JSONArray();
        }
    }

    /**
     * 同比趋势分析
     *
     * @param compareTrendDTO 查询对象
     * @return 查询结果
     */
    @Override
    public List<CompareTrendVO> compareTrendAnalyze(CompareTrendDTO compareTrendDTO) {
        List<PollFactorInfoEntity> factorInfoList = null;
        final List<Long> factorList = compareTrendDTO.getMonitorFactorList();
        if (CollectionUtils.isEmpty(factorList)) {
            final Long monitorSiteId = compareTrendDTO.getMonitorSiteId();
            final PollMonitorSiteEntity pollMonitorSiteEntity = pollMonitorSiteService.getById(monitorSiteId);
            if (null != pollMonitorSiteEntity.getMonitorType()) {
                factorInfoList = pollDisplayFactorService.getDisplayFactorByMonitorType(pollMonitorSiteEntity.getMonitorType());
            }
        } else {
            final LambdaQueryWrapper<PollFactorInfoEntity> wrapper = Wrappers.
                    <PollFactorInfoEntity>lambdaQuery().in(CollectionUtils.isNotEmpty(factorList), PollFactorInfoEntity::getId, factorList);
            factorInfoList = pollFactorInfoService.list(wrapper);
        }
        if (CollectionUtils.isEmpty(factorInfoList)) {
            return null;
        }
        if (compareTrendDTO.getDateType().equals(AnalyzeTrendConstant.DATA_TYPE_MIN)) {
            return compareOmMinTrend(compareTrendDTO, factorInfoList, DateUtils::dateLimitMinute);
        } else if (compareTrendDTO.getDateType().equals(AnalyzeTrendConstant.DATA_TYPE_HOUR)) {
            return compareOmHourTrend(compareTrendDTO, factorInfoList, DateUtils::dateLimitHour);
        } else if (compareTrendDTO.getDateType().equals(AnalyzeTrendConstant.DATA_TYPE_DAY)) {
            return compareOmDayTrend(compareTrendDTO, factorInfoList, DateUtils::dateLimitDay);
        }
        return null;
    }


    /**
     * 同比分析分钟数据趋势
     *
     * @param compareTrendDTO 查询对象
     * @param factorInfoList  选择的因子
     * @param mapper          时间处理函数
     * @return 结果
     */
    private List<CompareTrendVO> compareOmMinTrend(CompareTrendDTO compareTrendDTO, List<PollFactorInfoEntity> factorInfoList, Function<Date, Date> mapper) {
        // step 1 时间处理
        final Date beginTime = mapper.apply(compareTrendDTO.getBeginTime());
        final Date endTime = mapper.apply(compareTrendDTO.getEndTime());
        final int timeInterval = Long.valueOf(endTime.getTime() - beginTime.getTime()).intValue();
        final List<String> dateTimeList = handlerDateTime(beginTime, endTime, DateUtils::limitMinute, Calendar.MINUTE,
                AnalyzeTrendConstant.MINUTE_DATA_INTERVAL_5);
        // step 2 数据库查询
        final Long monitorSiteId = compareTrendDTO.getMonitorSiteId();
        final List<Long> monitorSiteList = Collections.singletonList(monitorSiteId);
        final List<BaseOmDataEntity> currentOmData = pollMinService.listOmMinByDateRangeAndSite(beginTime, endTime, monitorSiteList);

        // step 3 判断是否存在同比
        List<BaseOmDataEntity> compareOmData = null;
        if (null != compareTrendDTO.getCompareBeginTime()) {
            final Date compareBeginTime = mapper.apply(compareTrendDTO.getCompareBeginTime());
            final Date compareEndTime = DateUtils.add(compareBeginTime, Calendar.MILLISECOND, timeInterval);
            compareOmData = pollMinService.listOmMinByDateRangeAndSite(compareBeginTime, compareEndTime, monitorSiteList);
        }

        // step 4 构建数据
        return super.buildCompareTrendList(monitorSiteId, compareTrendDTO.getDataAnalyzeType(), dateTimeList, factorInfoList, DateUtils::limitMinute, currentOmData, compareOmData);
    }

    private List<CompareTrendVO> compareOmHourTrend(CompareTrendDTO compareTrendDTO, List<PollFactorInfoEntity> factorInfoList, Function<Date, Date> mapper) {
        // step 1 时间处理
        final Date beginTime = mapper.apply(compareTrendDTO.getBeginTime());
        final Date endTime = mapper.apply(compareTrendDTO.getEndTime());
        final int timeInterval = Long.valueOf(endTime.getTime() - beginTime.getTime()).intValue();
        final List<String> dateTimeList = handlerDateTime(beginTime, endTime, DateUtils::limitMinute, Calendar.HOUR_OF_DAY, AnalyzeTrendConstant.HOUR_DATA_INTERVAL_1);
        // step 2 数据库查询
        final Long monitorSiteId = compareTrendDTO.getMonitorSiteId();
        final List<Long> monitorSiteList = Collections.singletonList(monitorSiteId);
        final List<BaseOmDataEntity> currentOmData = pollHourService.listOmHourByDateRangeAndSite(beginTime, endTime, monitorSiteList);

        // step 3 判断是否存在同比
        List<BaseOmDataEntity> compareOmData = null;
        if (null != compareTrendDTO.getCompareBeginTime()) {
            final Date compareBeginTime = mapper.apply(compareTrendDTO.getCompareBeginTime());
            final Date compareEndTime = DateUtils.add(compareBeginTime, Calendar.MILLISECOND, timeInterval);
            compareOmData = pollHourService.listOmHourByDateRangeAndSite(compareBeginTime, compareEndTime, monitorSiteList);
        }

        // step 4 构建数据
        return super.buildCompareTrendList(monitorSiteId, compareTrendDTO.getDataAnalyzeType(), dateTimeList, factorInfoList, DateUtils::limitHour, currentOmData, compareOmData);
    }

    private List<CompareTrendVO> compareOmDayTrend(CompareTrendDTO compareTrendDTO, List<PollFactorInfoEntity> factorInfoList, Function<Date, Date> mapper) {
        // step 1 时间处理
        final Date beginTime = mapper.apply(compareTrendDTO.getBeginTime());
        final Date endTime = mapper.apply(compareTrendDTO.getEndTime());
        final int timeInterval = Long.valueOf(endTime.getTime() - beginTime.getTime()).intValue();
        final List<String> dateTimeList = handlerDateTime(beginTime, endTime, DateUtils::limitMinute, Calendar.DAY_OF_YEAR, AnalyzeTrendConstant.DAY_DATA_INTERVAL_1);
        // step 2 数据库查询
        final Long monitorSiteId = compareTrendDTO.getMonitorSiteId();
        final List<Long> monitorSiteList = Collections.singletonList(monitorSiteId);
        final List<BaseOmDataEntity> currentOmData = pollDayService.listOmDayByDateRangeAndSite(beginTime, endTime, monitorSiteList);

        // step 3 判断是否存在同比
        List<BaseOmDataEntity> compareOmData = null;
        if (null != compareTrendDTO.getCompareBeginTime()) {
            final Date compareBeginTime = mapper.apply(compareTrendDTO.getCompareBeginTime());
            final Date compareEndTime = DateUtils.add(compareBeginTime, Calendar.MILLISECOND, timeInterval);
            compareOmData = pollDayService.listOmDayByDateRangeAndSite(compareBeginTime, compareEndTime, monitorSiteList);
        }

        // step 4 构建数据
        return super.buildCompareTrendList(monitorSiteId, compareTrendDTO.getDataAnalyzeType(), dateTimeList, factorInfoList, DateUtils::limitDay, currentOmData, compareOmData);
    }

    @Override
    public JSONObject gisAnalyzeDischarge(GISAnalyzeDischargeDTO gisAnalyzeDischargeDTO) {
        // 获取全部展示因子
        List<PollDisplayFactorEntity> factorEntities = pollDisplayFactorService.list();
        List<String> factorIds = new ArrayList<>();
        for (PollDisplayFactorEntity factorEntity : factorEntities) {
            String ids = factorEntity.getFactorIds();
            if (StringUtils.isNotBlank(ids)) {
                factorIds.addAll(Objects.requireNonNull(CollectionUtils.arrayToList(ids.split(","))));
            }
        }
        LambdaQueryWrapper<PollFactorInfoEntity> factorWrapper = Wrappers.lambdaQuery();
        factorWrapper.in(CollectionUtils.isNotEmpty(factorIds), PollFactorInfoEntity::getId, factorIds);
        List<PollFactorInfoEntity> factorInfoList = pollFactorInfoService.list(factorWrapper);

        Date now = new Date();
        String type = gisAnalyzeDischargeDTO.getType();

        if (GISAnalyzeConstant.DAY.equals(type)) {
            Date his = DateUtils.addDate(now, -29);
            LambdaQueryWrapper<PollDayEntity> dayWrapper = Wrappers.lambdaQuery();
            dayWrapper.ge(PollDayEntity::getDataTime, his);
            dayWrapper.le(PollDayEntity::getDataTime, now);
            List<PollDayEntity> list = pollDayService.list(dayWrapper);

            List<String> dateTimeList = super.handlerDateTime(his, now, DateUtils::limitDay, Calendar.DAY_OF_YEAR, 1);

            return super.handlerDataGIS(dateTimeList, factorInfoList, list, DateUtils::limitDay);
        } else if (GISAnalyzeConstant.HOUR.equals(type)) {
            Date his = DateUtils.addHour(now, -23);
            LambdaQueryWrapper<PollHourEntity> hourWrapper = Wrappers.lambdaQuery();
            hourWrapper.ge(PollHourEntity::getDataTime, his);
            hourWrapper.le(PollHourEntity::getDataTime, now);
            List<PollHourEntity> list = pollHourService.list(hourWrapper);

            List<String> dateTimeList = super.handlerDateTime(his, now, DateUtils::limitHour, Calendar.HOUR_OF_DAY, 1);

            return super.handlerDataGIS(dateTimeList, factorInfoList, list, DateUtils::limitHour);
        }

        return new JSONObject();
    }

    @Override
    public CompareAnalysisVo compareAnalysis(CompareAnalysisDTO compareAnalysisDTO) {
        // 查询因子
        Long monitorSiteId = compareAnalysisDTO.getMonitorSiteId();
        List<PollFactorInfoEntity> factorInfoList = getFactorInfoList(monitorSiteId, compareAnalysisDTO.getMonitorFactorList());
        // 查询同比数据
        Integer dataType = compareAnalysisDTO.getDataType();
        Date analysisTime = compareAnalysisDTO.getAnalysisTime();
        Date compareTime = compareAnalysisDTO.getCompareTime();
        BaseOmDataEntity analysisOmData = pollHisDataService.getByMonitorSiteIdAndDataTime(monitorSiteId, analysisTime, dataType);
        BaseOmDataEntity compareOmData = pollHisDataService.getByMonitorSiteIdAndDataTime(monitorSiteId, compareTime, dataType);
        // 构建数据
        CompareAnalysisVo compareAnalysisVo = buildCompareAnalysisData(analysisOmData, compareOmData, factorInfoList, compareAnalysisDTO.getDataAnalyzeType());
        compareAnalysisVo.setAnalysisDataName(PollDataTimeParse.format(analysisTime, dataType));
        compareAnalysisVo.setCompareDataName(PollDataTimeParse.format(compareTime, dataType));
        return compareAnalysisVo;
    }

    private CompareAnalysisVo buildCompareAnalysisData(BaseOmDataEntity analysisOmData, BaseOmDataEntity compareOmData, List<PollFactorInfoEntity> factorInfoList, Integer dataAnalyzeType) {
        CompareAnalysisVo compareAnalysisVo = new CompareAnalysisVo();
        List<String> factor = new ArrayList<>(factorInfoList.size());
        List<Double> analysisDataList = new ArrayList<>(factorInfoList.size());
        List<Double> compareDataList = new ArrayList<>(factorInfoList.size());

        String key = AnalyzeTrendConstant.ANALYZE_DATA_TYPE_MAP.get(dataAnalyzeType);
        for (PollFactorInfoEntity factorInfo : factorInfoList) {
            factor.add(factorInfo.getName());
            String code = factorInfo.getCode();
            Double analysisVal = Optional.ofNullable(analysisOmData).map(BaseOmDataEntity::getDataJson)
                    .map(json -> json.getJSONObject(code))
                    .map(data -> data.getDouble(key)).orElse(0d);

            Double compareVal = Optional.ofNullable(compareOmData).map(BaseOmDataEntity::getDataJson)
                    .map(json -> json.getJSONObject(code))
                    .map(data -> data.getDouble(key)).orElse(0d);
            analysisDataList.add(analysisVal);
            compareDataList.add(compareVal);
        }
        compareAnalysisVo.setFactor(factor);
        compareAnalysisVo.setAnalysisDataVal(analysisDataList);
        compareAnalysisVo.setCompareDataVal(compareDataList);
        return compareAnalysisVo;
    }

    private List<PollFactorInfoEntity> getFactorInfoList(Long monitorSiteId, List<Long> monitorFactorList) {
        List<Long> factorIdList = pollMonitorFactorService.lambdaQuery()
                .eq(PollMonitorFactorEntity::getMonitorSiteId, monitorSiteId)
                .select(PollMonitorFactorEntity::getFactorId)
                .list().stream().map(PollMonitorFactorEntity::getFactorId).collect(Collectors.toList());
        if (CollectionUtils.isNotEmpty(monitorFactorList)) {
            factorIdList = factorIdList.stream().filter(monitorFactorList::contains).collect(Collectors.toList());
        }
        return pollFactorInfoService.lambdaQuery()
                .in(PollFactorInfoEntity::getId, factorIdList)
                .list();
    }

    /**
     * 分析分钟数据趋势
     *
     * @param analyzeTrendDTO 查询对象
     * @return 结果
     */
    private JSONArray listOmMin(AnalyzeTrendDTO analyzeTrendDTO, List<PollMonitorSiteEntity> monitorSiteList,
                                List<PollFactorInfoEntity> monitorFactorList, List<String> factorCodeList, Function<Date, Date> mapper) {
        // step1、 时间处理
        final Date beginTime = mapper.apply(analyzeTrendDTO.getBeginTime());
        final Date endTime = mapper.apply(analyzeTrendDTO.getEndTime());
        final List<String> dateTimeList = super.handlerDateTime(beginTime, endTime, DateUtils::limitMinute, Calendar.MINUTE,
                AnalyzeTrendConstant.MINUTE_DATA_INTERVAL_5);
        // step2: 查询监测数据(所有选择的监控站点)
        final List<BaseOmDataEntity> pollDayEntityList = pollMinService.listOmMinList(analyzeTrendDTO, factorCodeList);
        // step3: 数据展示方式  单站多因子、 多站单因子
        return super.handlerDataDisplayType("分钟数据变化趋势", DateUtils::limitMinute, analyzeTrendDTO, monitorSiteList,
                dateTimeList, monitorFactorList, pollDayEntityList);
    }

    /**
     * 分析小时数据趋势
     *
     * @param analyzeTrendDTO 查询对象
     * @return 结果
     */
    private JSONArray listOmHour(AnalyzeTrendDTO analyzeTrendDTO, List<PollMonitorSiteEntity> monitorSiteList,
                                 List<PollFactorInfoEntity> monitorFactorList, List<String> factorCodeList, Function<Date, Date> mapper) {
        // step1、 时间处理
        final Date beginTime = mapper.apply(analyzeTrendDTO.getBeginTime());
        final Date endTime = mapper.apply(analyzeTrendDTO.getEndTime());
        final List<String> dateTimeList = super.handlerDateTime(beginTime, endTime, DateUtils::limitHour, Calendar.HOUR_OF_DAY, 1);
        // step2: 查询监测数据(所有选择的监控站点)
        final List<BaseOmDataEntity> pollDayEntityList = pollHourService.listOmHourList(analyzeTrendDTO, factorCodeList);
        // step3: 数据展示方式  单站多因子、 多站单因子
        return super.handlerDataDisplayType("小时数据变化趋势", DateUtils::limitHour, analyzeTrendDTO, monitorSiteList,
                dateTimeList, monitorFactorList, pollDayEntityList);
    }


    /**
     * 分析某天数据趋势
     *
     * @param analyzeTrendDTO 查询对象
     * @return 结果
     */
    private JSONArray listOmDay(AnalyzeTrendDTO analyzeTrendDTO, List<PollMonitorSiteEntity> monitorSiteList,
                                List<PollFactorInfoEntity> monitorFactorList, List<String> factorCodeList, Function<Date, Date> mapper) {
        // step1、 时间处理
        final Date beginTime = mapper.apply(analyzeTrendDTO.getBeginTime());
        final Date endTime = mapper.apply(analyzeTrendDTO.getEndTime());
        final List<String> dateTimeList = super.handlerDateTime(beginTime, endTime, DateUtils::limitDay, Calendar.DAY_OF_YEAR, 1);
        // step2: 查询监测数据(所有选择的监控站点)
        final List<BaseOmDataEntity> pollDayEntityList = pollDayService.listOmDayList(analyzeTrendDTO, factorCodeList);
        // step3: 数据展示方式  单站多因子、 多站单因子
        return super.handlerDataDisplayType("日数据变化趋势", DateUtils::limitDay, analyzeTrendDTO, monitorSiteList,
                dateTimeList, monitorFactorList, pollDayEntityList);
    }


}
